use std::{fmt, sync::Arc};

use async_trait::async_trait;
use axum::extract::Host;
use axum_extra::extract::{CookieJar, Multipart};
use http::Method;
use openapi::{
    apis::{pet::*, store::*, user::*, ApiKeyAuthHeader},
    models,
};
use tokio::{net::TcpListener, signal};

struct ServerImpl {
    // database: sea_orm::DbConn,
}

impl ApiKeyAuthHeader for ServerImpl {
    type Claims = String;

    #[doc = " Extracting Claims from Header. Return None if the Claims is invalid."]
    #[must_use]
    #[allow(
        elided_named_lifetimes,
        clippy::type_complexity,
        clippy::type_repetition_in_bounds
    )]
    fn extract_claims_from_header<'life0, 'life1, 'life2, 'async_trait>(
        &'life0 self,
        headers: &'life1 axum::http::header::HeaderMap,
        key: &'life2 str,
    ) -> ::core::pin::Pin<
        Box<
            dyn ::core::future::Future<Output = Option<Self::Claims>>
                + ::core::marker::Send
                + 'async_trait,
        >,
    >
    where
        'life0: 'async_trait,
        'life1: 'async_trait,
        'life2: 'async_trait,
        Self: 'async_trait,
    {
        for (k, v) in headers {
            println!("{},{}", k.as_str(), v.to_str().unwrap())
        }
        Box::pin(async { Option::Some("1".to_string()) })
    }
}

impl Store for ServerImpl {
    type Claims = String;

    #[doc = " Delete purchase order by ID."]
    #[doc = ""]
    #[doc = " DeleteOrder - DELETE /v2/store/order/{orderId}"]
    #[must_use]
    #[allow(
        elided_named_lifetimes,
        clippy::type_complexity,
        clippy::type_repetition_in_bounds
    )]
    fn delete_order<'life0, 'async_trait>(
        &'life0 self,
        method: Method,
        host: Host,
        cookies: CookieJar,
        path_params: models::DeleteOrderPathParams,
    ) -> ::core::pin::Pin<
        Box<
            dyn ::core::future::Future<Output = Result<DeleteOrderResponse, ()>>
                + ::core::marker::Send
                + 'async_trait,
        >,
    >
    where
        'life0: 'async_trait,
        Self: 'async_trait,
    {
        todo!()
    }

    #[doc = " Returns pet inventories by status."]
    #[doc = ""]
    #[doc = " GetInventory - GET /v2/store/inventory"]
    #[must_use]
    #[allow(
        elided_named_lifetimes,
        clippy::type_complexity,
        clippy::type_repetition_in_bounds
    )]
    fn get_inventory<'life0, 'async_trait>(
        &'life0 self,
        method: Method,
        host: Host,
        cookies: CookieJar,
        claims: Self::Claims,
    ) -> ::core::pin::Pin<
        Box<
            dyn ::core::future::Future<Output = Result<GetInventoryResponse, ()>>
                + ::core::marker::Send
                + 'async_trait,
        >,
    >
    where
        'life0: 'async_trait,
        Self: 'async_trait,
    {
        todo!()
    }

    #[doc = " Find purchase order by ID."]
    #[doc = ""]
    #[doc = " GetOrderById - GET /v2/store/order/{orderId}"]
    #[must_use]
    #[allow(
        elided_named_lifetimes,
        clippy::type_complexity,
        clippy::type_repetition_in_bounds
    )]
    fn get_order_by_id<'life0, 'async_trait>(
        &'life0 self,
        method: Method,
        host: Host,
        cookies: CookieJar,
        path_params: models::GetOrderByIdPathParams,
    ) -> ::core::pin::Pin<
        Box<
            dyn ::core::future::Future<Output = Result<GetOrderByIdResponse, ()>>
                + ::core::marker::Send
                + 'async_trait,
        >,
    >
    where
        'life0: 'async_trait,
        Self: 'async_trait,
    {
        todo!()
    }

    #[doc = " Place an order for a pet."]
    #[doc = ""]
    #[doc = " PlaceOrder - POST /v2/store/order"]
    #[must_use]
    #[allow(
        elided_named_lifetimes,
        clippy::type_complexity,
        clippy::type_repetition_in_bounds
    )]
    fn place_order<'life0, 'async_trait>(
        &'life0 self,
        method: Method,
        host: Host,
        cookies: CookieJar,
        body: models::Order,
    ) -> ::core::pin::Pin<
        Box<
            dyn ::core::future::Future<Output = Result<PlaceOrderResponse, ()>>
                + ::core::marker::Send
                + 'async_trait,
        >,
    >
    where
        'life0: 'async_trait,
        Self: 'async_trait,
    {
        todo!()
    }
}

impl User for ServerImpl {
    type Claims = String;

    #[doc = " Create user."]
    #[doc = ""]
    #[doc = " CreateUser - POST /v2/user"]
    #[must_use]
    #[allow(
        elided_named_lifetimes,
        clippy::type_complexity,
        clippy::type_repetition_in_bounds
    )]
    fn create_user<'life0, 'async_trait>(
        &'life0 self,
        method: Method,
        host: Host,
        cookies: CookieJar,
        claims: Self::Claims,
        body: models::User,
    ) -> ::core::pin::Pin<
        Box<
            dyn ::core::future::Future<Output = Result<CreateUserResponse, ()>>
                + ::core::marker::Send
                + 'async_trait,
        >,
    >
    where
        'life0: 'async_trait,
        Self: 'async_trait,
    {
        todo!()
    }

    #[doc = " Creates list of users with given input array."]
    #[doc = ""]
    #[doc = " CreateUsersWithArrayInput - POST /v2/user/createWithArray"]
    #[must_use]
    #[allow(
        elided_named_lifetimes,
        clippy::type_complexity,
        clippy::type_repetition_in_bounds
    )]
    fn create_users_with_array_input<'life0, 'async_trait>(
        &'life0 self,
        method: Method,
        host: Host,
        cookies: CookieJar,
        claims: Self::Claims,
        body: Vec<models::User>,
    ) -> ::core::pin::Pin<
        Box<
            dyn ::core::future::Future<Output = Result<CreateUsersWithArrayInputResponse, ()>>
                + ::core::marker::Send
                + 'async_trait,
        >,
    >
    where
        'life0: 'async_trait,
        Self: 'async_trait,
    {
        todo!()
    }

    #[doc = " Creates list of users with given input array."]
    #[doc = ""]
    #[doc = " CreateUsersWithListInput - POST /v2/user/createWithList"]
    #[must_use]
    #[allow(
        elided_named_lifetimes,
        clippy::type_complexity,
        clippy::type_repetition_in_bounds
    )]
    fn create_users_with_list_input<'life0, 'async_trait>(
        &'life0 self,
        method: Method,
        host: Host,
        cookies: CookieJar,
        claims: Self::Claims,
        body: Vec<models::User>,
    ) -> ::core::pin::Pin<
        Box<
            dyn ::core::future::Future<Output = Result<CreateUsersWithListInputResponse, ()>>
                + ::core::marker::Send
                + 'async_trait,
        >,
    >
    where
        'life0: 'async_trait,
        Self: 'async_trait,
    {
        todo!()
    }

    #[doc = " Delete user."]
    #[doc = ""]
    #[doc = " DeleteUser - DELETE /v2/user/{username}"]
    #[must_use]
    #[allow(
        elided_named_lifetimes,
        clippy::type_complexity,
        clippy::type_repetition_in_bounds
    )]
    fn delete_user<'life0, 'async_trait>(
        &'life0 self,
        method: Method,
        host: Host,
        cookies: CookieJar,
        claims: Self::Claims,
        path_params: models::DeleteUserPathParams,
    ) -> ::core::pin::Pin<
        Box<
            dyn ::core::future::Future<Output = Result<DeleteUserResponse, ()>>
                + ::core::marker::Send
                + 'async_trait,
        >,
    >
    where
        'life0: 'async_trait,
        Self: 'async_trait,
    {
        todo!()
    }

    #[doc = " Get user by user name."]
    #[doc = ""]
    #[doc = " GetUserByName - GET /v2/user/{username}"]
    #[must_use]
    #[allow(
        elided_named_lifetimes,
        clippy::type_complexity,
        clippy::type_repetition_in_bounds
    )]
    fn get_user_by_name<'life0, 'async_trait>(
        &'life0 self,
        method: Method,
        host: Host,
        cookies: CookieJar,
        path_params: models::GetUserByNamePathParams,
    ) -> ::core::pin::Pin<
        Box<
            dyn ::core::future::Future<Output = Result<GetUserByNameResponse, ()>>
                + ::core::marker::Send
                + 'async_trait,
        >,
    >
    where
        'life0: 'async_trait,
        Self: 'async_trait,
    {
        todo!()
    }

    #[doc = " Logs user into the system."]
    #[doc = ""]
    #[doc = " LoginUser - GET /v2/user/login"]
    #[must_use]
    #[allow(
        elided_named_lifetimes,
        clippy::type_complexity,
        clippy::type_repetition_in_bounds
    )]
    fn login_user<'life0, 'async_trait>(
        &'life0 self,
        method: Method,
        host: Host,
        cookies: CookieJar,
        query_params: models::LoginUserQueryParams,
    ) -> ::core::pin::Pin<
        Box<
            dyn ::core::future::Future<Output = Result<LoginUserResponse, ()>>
                + ::core::marker::Send
                + 'async_trait,
        >,
    >
    where
        'life0: 'async_trait,
        Self: 'async_trait,
    {
        todo!()
    }

    #[doc = " Logs out current logged in user session."]
    #[doc = ""]
    #[doc = " LogoutUser - GET /v2/user/logout"]
    #[must_use]
    #[allow(
        elided_named_lifetimes,
        clippy::type_complexity,
        clippy::type_repetition_in_bounds
    )]
    fn logout_user<'life0, 'async_trait>(
        &'life0 self,
        method: Method,
        host: Host,
        cookies: CookieJar,
        claims: Self::Claims,
    ) -> ::core::pin::Pin<
        Box<
            dyn ::core::future::Future<Output = Result<LogoutUserResponse, ()>>
                + ::core::marker::Send
                + 'async_trait,
        >,
    >
    where
        'life0: 'async_trait,
        Self: 'async_trait,
    {
        todo!()
    }

    #[doc = " Updated user."]
    #[doc = ""]
    #[doc = " UpdateUser - PUT /v2/user/{username}"]
    #[must_use]
    #[allow(
        elided_named_lifetimes,
        clippy::type_complexity,
        clippy::type_repetition_in_bounds
    )]
    fn update_user<'life0, 'async_trait>(
        &'life0 self,
        method: Method,
        host: Host,
        cookies: CookieJar,
        claims: Self::Claims,
        path_params: models::UpdateUserPathParams,
        body: models::User,
    ) -> ::core::pin::Pin<
        Box<
            dyn ::core::future::Future<Output = Result<UpdateUserResponse, ()>>
                + ::core::marker::Send
                + 'async_trait,
        >,
    >
    where
        'life0: 'async_trait,
        Self: 'async_trait,
    {
        todo!()
    }
}

impl Pet for ServerImpl {
    type Claims = String;

    #[doc = " Add a new pet to the store."]
    #[doc = ""]
    #[doc = " AddPet - POST /v2/pet"]
    #[must_use]
    #[allow(
        elided_named_lifetimes,
        clippy::type_complexity,
        clippy::type_repetition_in_bounds
    )]
    fn add_pet<'life0, 'async_trait>(
        &'life0 self,
        method: Method,
        host: Host,
        cookies: CookieJar,
        body: models::Pet,
    ) -> ::core::pin::Pin<
        Box<
            dyn ::core::future::Future<Output = Result<AddPetResponse, ()>>
                + ::core::marker::Send
                + 'async_trait,
        >,
    >
    where
        'life0: 'async_trait,
        Self: 'async_trait,
    {
        todo!()
    }

    #[doc = " Deletes a pet."]
    #[doc = ""]
    #[doc = " DeletePet - DELETE /v2/pet/{petId}"]
    #[must_use]
    #[allow(
        elided_named_lifetimes,
        clippy::type_complexity,
        clippy::type_repetition_in_bounds
    )]
    fn delete_pet<'life0, 'async_trait>(
        &'life0 self,
        method: Method,
        host: Host,
        cookies: CookieJar,
        header_params: models::DeletePetHeaderParams,
        path_params: models::DeletePetPathParams,
    ) -> ::core::pin::Pin<
        Box<
            dyn ::core::future::Future<Output = Result<DeletePetResponse, ()>>
                + ::core::marker::Send
                + 'async_trait,
        >,
    >
    where
        'life0: 'async_trait,
        Self: 'async_trait,
    {
        todo!()
    }

    #[doc = " Finds Pets by status."]
    #[doc = ""]
    #[doc = " FindPetsByStatus - GET /v2/pet/findByStatus"]
    #[must_use]
    #[allow(
        elided_named_lifetimes,
        clippy::type_complexity,
        clippy::type_repetition_in_bounds
    )]
    fn find_pets_by_status<'life0, 'async_trait>(
        &'life0 self,
        method: Method,
        host: Host,
        cookies: CookieJar,
        query_params: models::FindPetsByStatusQueryParams,
    ) -> ::core::pin::Pin<
        Box<
            dyn ::core::future::Future<Output = Result<FindPetsByStatusResponse, ()>>
                + ::core::marker::Send
                + 'async_trait,
        >,
    >
    where
        'life0: 'async_trait,
        Self: 'async_trait,
    {
        todo!()
    }

    #[doc = " Finds Pets by tags."]
    #[doc = ""]
    #[doc = " FindPetsByTags - GET /v2/pet/findByTags"]
    #[must_use]
    #[allow(
        elided_named_lifetimes,
        clippy::type_complexity,
        clippy::type_repetition_in_bounds
    )]
    fn find_pets_by_tags<'life0, 'async_trait>(
        &'life0 self,
        method: Method,
        host: Host,
        cookies: CookieJar,
        query_params: models::FindPetsByTagsQueryParams,
    ) -> ::core::pin::Pin<
        Box<
            dyn ::core::future::Future<Output = Result<FindPetsByTagsResponse, ()>>
                + ::core::marker::Send
                + 'async_trait,
        >,
    >
    where
        'life0: 'async_trait,
        Self: 'async_trait,
    {
        todo!()
    }

    #[doc = " Find pet by ID."]
    #[doc = ""]
    #[doc = " GetPetById - GET /v2/pet/{petId}"]
    #[must_use]
    #[allow(
        elided_named_lifetimes,
        clippy::type_complexity,
        clippy::type_repetition_in_bounds
    )]
    fn get_pet_by_id<'life0, 'async_trait>(
        &'life0 self,
        method: Method,
        host: Host,
        cookies: CookieJar,
        claims: Self::Claims,
        path_params: models::GetPetByIdPathParams,
    ) -> ::core::pin::Pin<
        Box<
            dyn ::core::future::Future<Output = Result<GetPetByIdResponse, ()>>
                + ::core::marker::Send
                + 'async_trait,
        >,
    >
    where
        'life0: 'async_trait,
        Self: 'async_trait,
    {
        let result = async {
            Ok(GetPetByIdResponse::Status200_SuccessfulOperation(
                String::from("hello"),
            ))
        };
        Box::pin(result)
    }

    #[doc = " Update an existing pet."]
    #[doc = ""]
    #[doc = " UpdatePet - PUT /v2/pet"]
    #[must_use]
    #[allow(
        elided_named_lifetimes,
        clippy::type_complexity,
        clippy::type_repetition_in_bounds
    )]
    fn update_pet<'life0, 'async_trait>(
        &'life0 self,
        method: Method,
        host: Host,
        cookies: CookieJar,
        body: models::Pet,
    ) -> ::core::pin::Pin<
        Box<
            dyn ::core::future::Future<Output = Result<UpdatePetResponse, ()>>
                + ::core::marker::Send
                + 'async_trait,
        >,
    >
    where
        'life0: 'async_trait,
        Self: 'async_trait,
    {
        todo!()
    }

    #[doc = " Updates a pet in the store with form data."]
    #[doc = ""]
    #[doc = " UpdatePetWithForm - POST /v2/pet/{petId}"]
    #[must_use]
    #[allow(
        elided_named_lifetimes,
        clippy::type_complexity,
        clippy::type_repetition_in_bounds
    )]
    fn update_pet_with_form<'life0, 'async_trait>(
        &'life0 self,
        method: Method,
        host: Host,
        cookies: CookieJar,
        path_params: models::UpdatePetWithFormPathParams,
        body: Option<models::UpdatePetWithFormRequest>,
    ) -> ::core::pin::Pin<
        Box<
            dyn ::core::future::Future<Output = Result<UpdatePetWithFormResponse, ()>>
                + ::core::marker::Send
                + 'async_trait,
        >,
    >
    where
        'life0: 'async_trait,
        Self: 'async_trait,
    {
        todo!()
    }

    #[doc = " uploads an image."]
    #[doc = ""]
    #[doc = " UploadFile - POST /v2/pet/{petId}/uploadImage"]
    #[must_use]
    #[allow(
        elided_named_lifetimes,
        clippy::type_complexity,
        clippy::type_repetition_in_bounds
    )]
    fn upload_file<'life0, 'async_trait>(
        &'life0 self,
        method: Method,
        host: Host,
        cookies: CookieJar,
        path_params: models::UploadFilePathParams,
        body: Multipart,
    ) -> ::core::pin::Pin<
        Box<
            dyn ::core::future::Future<Output = Result<UploadFileResponse, ()>>
                + ::core::marker::Send
                + 'async_trait,
        >,
    >
    where
        'life0: 'async_trait,
        Self: 'async_trait,
    {
        todo!()
    }
}

pub async fn start_server(addr: &str) {
    // initialize tracing
    tracing_subscriber::fmt::init();

    let server = ServerImpl {};

    // Init Axum router
    let app = openapi::server::new(Arc::new(server));

    // Add layers to the router
    //let app = app.layer(...);

    // Run the server with graceful shutdown
    let listener = TcpListener::bind(addr).await.unwrap();
    axum::serve(listener, app)
        .with_graceful_shutdown(shutdown_signal())
        .await
        .unwrap();
}

async fn shutdown_signal() {
    let ctrl_c = async {
        signal::ctrl_c()
            .await
            .expect("failed to install Ctrl+C handler");
    };

    #[cfg(unix)]
    let terminate = async {
        signal::unix::signal(signal::unix::SignalKind::terminate())
            .expect("failed to install signal handler")
            .recv()
            .await;
    };

    #[cfg(not(unix))]
    let terminate = std::future::pending::<()>();

    tokio::select! {
        _ = ctrl_c => {},
        _ = terminate => {},
    }
}
